iT邦幫忙

2025 iThome 鐵人賽

DAY 29
0
自我挑戰組

請問這是魔法嗎?前端轉職菜雞的修煉之路!系列 第 29

DAY 29 從特例到預設的魔法 - Next.js 的 Server Side Render

  • 分享至 

  • xImage
  •  

當初在面試時,被問到 Next.js 的 Server Side Render,想在這裡整理一下:

先介紹一下什麼是 Server Side Render:
在傳統的 React SPA(Single Page Application)中,使用者請求後,瀏覽器會先下載一個空的 index.html,再由 JS 在客戶端「渲染出整個畫面」。但這樣搜尋引擎的爬蟲可能只看到一個空頁,導致 SEO 不佳;使用者首次請求頁面時,也需要等待 JS bundle 下載和執行,導致使用者體驗不佳。
而 Server Side Render,則會在使用者請求後,先由 Next.js 伺服器將 React 的元件渲染成 html,JS 再在前端進行「hydration(注水、水合)」,讓靜態的 HTML 變成有互動的應用,同時能避免上述 SPA 的問題。

在 Next.js 12 以前,採用的是 Page Router。它的 SSR 實作方式主要是透過 getServerSideProps 函式來實現。什麼是 getServerSideProps 函式?它是 Next.js 提供的預先取資料的函式,流程如下:

  1. Next.js 伺服器會先執行這個函式。
  2. 它的回傳結果(props)會被傳入頁面組件中。
  3. Next.js 把頁面 預先渲染成 html,再送給使用者。

來看個範例:

// pages/profile.js
export async function getServerSideProps(context) {
  const res = await fetch('https://api.example.com/user')
  const user = await res.json()

  return {
    props: { user }, // 傳給下方的 component
  }
}

export default function ProfilePage({ user }) {
  return <div>Hello, {user.name}</div>
}

當使用者請求 /profile,Next.js 伺服器先執行 getServerSideProps(),取得資料 (fetch),再渲染 html Hello, Alice,html 再將交給瀏覽器,前端再 hydration。
getServerSideProps 實現了 SSR,但它也有一些缺點與限制:

  1. 每次請求頁面都必須等待 Next.js 伺服器執行,當頁面流量大、API 反應慢時,伺服器負載會變重、回應時間變長,效能會明顯下降。
  2. 無法進行部分快取,即使頁面中只有部分區塊需要即時更新,也必須整個頁面重新生成。
  3. 資料流不自然、邏輯分散,資料取得 (getServerSideProps) 和 UI 組件分開定義,開發者需要在函式中撰寫 fetch,再透過 props 傳遞進頁面組件。
  4. 無法支援串流渲染,必須等所有資料取得完畢後,才能一次性回傳整個 html。
  5. 只會在 Next.js 伺服器端執行,無法使用瀏覽器 API。

在 Next.js 13 推出的 App Router 架構中,官方徹底重構了 SSR 的運作方式,不再使用 getServerSideProps 來觸發伺服器端渲染,轉而使用了 React Server Components (RSC) 架構。在 App Router 中,預設每個檔案都是 Server Component,他的執行流程有什麼不同呢?直接來看範例:

// app/profile/page.tsx
export default async function ProfilePage() {
  const res = await fetch("https://api.example.com/user", { cache: "no-store" });
  const data = await res.json();

  return (
    <div>
      <h1>{data.name}</h1>
      <p>{data.email}</p>
    </div>
  );
}

當使用者請求 /profile,Next.js 伺服器判斷這是要渲染 App Router 的頁面後,就會進入 React Server Components (RSC) 的執行階段,在伺服器中執行 fetch ,並組成 React Server Components Tree(RSC tree),不同於過去 Page Router 時代直接回傳完整的 html,Next.js 會先產生一份 React Server Components Payload (RSC Payload),同時再生成對應的 html 給首次請求的使用者。瀏覽器接收到 html 後,而前端 JS 隨後進行 hydration,將靜態的 html 轉換為可互動的 React 元件。

這邊再補充一下:

  • RSC Tree 就是在伺服器端的 React 元件樹,也就是伺服器在接到請求時,依照頁面和組件的結構,把每個 Server Component 執行後的結果組成的一棵樹。它記錄了每個元件需要哪些資料、props 以及組件之間的關係,但還不是 html。可以把它想像成「伺服器端的完整食譜」,描述了要如何生成最終頁面。
  • RSC Payload 則是將這棵樹 序列化後傳給前端的資料包。前端 React 解析 Payload,把它轉換成可互動的元件(hydration)。支援 Streaming SSR,可以邊接收 Payload 邊渲染畫面,不必等整個樹生成完才顯示頁面。可以想像成「打包好的食材材料」,前端拿到材料就能快速組成完整餐點(html + 可互動元件)。

總結來說,Next.js 的 SSR 由 Page Router 到 App Router 的演進,其核心是 將伺服器端渲染更自然地融入 React 組件架構。

  • Page Router (getServerSideProps):SSR 是額外的函式,需要在伺服器單獨執行,資料與 UI 分離,開發上容易感到不直覺,效能與快取彈性也有限。
  • App Router (Server Components + RSC):SSR 成為元件本身的特性,資料可以直接在 async 元件中取得,支援 streaming、局部更新,開發者只需關注組件本身的邏輯,程式碼更乾淨、可組合性更高。

上一篇
DAY 28 瀏覽目錄的魔法 - Hoisting (2) - function
下一篇
DAY 30 後記
系列文
請問這是魔法嗎?前端轉職菜雞的修煉之路!30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言